/*
 * InternalFrameDelegate.cpp  0.4.0 / Nov 30, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "InternalFrameDelegate.h"

#include "InternalFrameWidget.h"
#include "QCursorAdapter.h"

// InternalFrameDelegate :: Protected Constructor. -----------------------------

/*!
 * \brief Constructs new InternalFrameDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj InternalFrame java object
 */
InternalFrameDelegate::InternalFrameDelegate(JNIEnv *env, jobject obj)
  : WindowDelegate(env, obj, new QMdiSubWindow())
{
  m_internalWidget = new InternalFrameWidget(this);
  qMdiSubWindow()->setWidget(m_internalWidget);
  m_internalWidget->installEventFilter(this);
}

// InternalFrameDelegate :: Native Calls. --------------------------------------

/*!
 * \brief Inserts child.
 *
 * \param env the JNIEnv pointer
 * \param childDelegate the child delegate pointer
 * \param index the child index
 */
void InternalFrameDelegate::insertChild(JNIEnv *env, jlong childDelegate,
                                        jint index)
{
  Q_ASSERT(env);
  SWING_REENTRANT(insertChild, SWING_ENV_ARG, JLONG_ARG(childDelegate),
                  JINT_ARG(index))
  ComponentDelegate *childComponentDelegate = COMPONENT_CAST(childDelegate);
  QWidget *childWidget = childComponentDelegate->qWidget();
  QRect geom = childWidget->geometry();
  childWidget->setParent(qMdiSubWidget());
  childComponentDelegate->setParentDelegate(this);
  if (!geom.isNull()) {
    childWidget->setGeometry(geom);
  }
  if (childWidget->isVisible()) {
    childWidget->setVisible(true);
  }
}

// InternalFrameDelegate :: Static Native Calls. -------------------------------

/*!
 * \brief Initializes InternalFrameDelegate class.
 *
 * \param env the JNIEnv pointer
 * \param cls the InternalFrame java class
 *
 * \exception FatalError if failed
 */
void InternalFrameDelegate::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(!sm_getLayoutPreferredSizeMID);
  if (!INIT_UMID(getLayoutPreferredSize, cls,
                "()Lcom/cute4j/swing/graphics/Dimension;")) {
    FATAL_LOGGED_ERROR("InternalFrameDelegate initialization failed");
  }
}

/*!
 * \brief Returns new instance of the delegate object
 *
 * \param env the JNIEnv pointer
 * \param obj the Swing object
 * 
 * \return new instance of the delegate object
 */
jlong InternalFrameDelegate::newInstance(JNIEnv *env, jobject obj)
{
  if (JNISwingWrapper::isSwingThread(env)) {
    return reinterpret_cast<jlong>(new InternalFrameDelegate(env, obj));
  }
  return SwingUtilitiesDelegate::invokeLongAndWait(env, obj, createMID());
}

// InternalFrameDelegate :: Native Callbacks. ----------------------------------

/*!
 * \brief Returns layout's preferred size.
 */
QSize InternalFrameDelegate::getLayoutPreferredSize()
{
  jobject preferredSize;
  if (jniObject()->callObjectMethod(preferredSize,
                                    sm_getLayoutPreferredSizeMID)) {
    jint preferredWidth;
    jint preferredHeight;
    DimensionObject preferredSizeDimension(jniObject()->env(), preferredSize);
    if (preferredSizeDimension.getWidth(preferredWidth) &&
        preferredSizeDimension.getHeight(preferredHeight)) {
      return QSize(preferredWidth, preferredHeight);
    }
  }
  return QSize();
}

// InternalFrameDelegate :: Overridden Member Function. ------------------------

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setFocusable(JNIEnv *env, jboolean focusable)
{
  Q_UNUSED(env);
  Q_UNUSED(focusable);
  // empty method
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::requestFocus(JNIEnv *env)
{
  Q_UNUSED(env);
  // empty method
}

/*!
 * \inheritDoc
 */
jobject InternalFrameDelegate::getBackground(JNIEnv *env, jclass colorClass)
{
  return QColorAdapter::toJColor(env, colorClass,
                          m_internalWidget->palette().color(QPalette::Window));
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setBackground(JNIEnv *env, jint argb)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setBackground, SWING_ENV_ARG, JINT_ARG(argb))
  QColorAdapter color(argb);
  QPalette palette(m_internalWidget->palette());
  if (color.isValid()) {
    m_internalWidget->setAutoFillBackground(true);
    palette.setColor(QPalette::Window, color);
  } else {
    m_internalWidget->setAutoFillBackground(false);
    palette.setColor(QPalette::Window,
                     QApplication::palette().color(QPalette::Window));
  }
  m_internalWidget->setPalette(palette);
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setNullBackground(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setNullBackground, SWING_ENV_ARG)
  QPalette palette(m_internalWidget->palette());
  palette.setColor(QPalette::Window,
                   QApplication::palette().color(QPalette::Window));
  m_internalWidget->setPalette(palette);
}

/*!
 * \inheritDoc
 */
jobject InternalFrameDelegate::getForeground(JNIEnv *env, jclass colorClass)
{
  return QColorAdapter::toJColor(env, colorClass,
                       m_internalWidget->palette().color(QPalette::WindowText));
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setForeground(JNIEnv *env, jint argb)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setForeground, SWING_ENV_ARG, JINT_ARG(argb))
  QColorAdapter color(argb);
  QPalette palette(m_internalWidget->palette());
  if (color.isValid()) {
    palette.setColor(QPalette::WindowText, color);
  } else {
    palette.setColor(QPalette::WindowText,
                     QApplication::palette().color(QPalette::WindowText));
  }
  m_internalWidget->setPalette(palette);
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setNullForeground(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setNullForeground, SWING_ENV_ARG)
  QPalette palette(m_internalWidget->palette());
  palette.setColor(QPalette::WindowText,
                   QApplication::palette().color(QPalette::WindowText));
  m_internalWidget->setPalette(palette);
}

/*!
 * \inheritDoc
 */
jobject InternalFrameDelegate::getFont(JNIEnv *env, jclass fontClass)
{
  return QFontAdapter::toJFont(env, fontClass, m_internalWidget->font());
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setFont(JNIEnv *env, jobject font)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setFont, SWING_ENV_ARG, JOBJECT_ARG(font))
  if (font) {
    m_internalWidget->setFont(*QFontAdapter::toQFont(env, font));
  } else {
    m_internalWidget->setFont(QFont());
  }
}

/*!
 * \inheritDoc
 */
jint InternalFrameDelegate::getCursor(JNIEnv *env)
{
  Q_UNUSED(env);
  return QCursorAdapter::cursorType(m_internalWidget->cursor());
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setCursor(JNIEnv *env, jint type)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setCursor, SWING_ENV_ARG, JINT_ARG(type))
  m_internalWidget->setCursor(QCursorAdapter(type));
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setComponentOrientation(JNIEnv *env,
                                                    jint orientation)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setComponentOrientation, SWING_ENV_ARG, JINT_ARG(orientation))
  switch(orientation) {
    case 1:
      m_internalWidget->unsetLayoutDirection();
      qMdiSubWindow()->unsetLayoutDirection();
      break;
    case 4:
      m_internalWidget->setLayoutDirection(Qt::LeftToRight);
      qMdiSubWindow()->setLayoutDirection(Qt::LeftToRight);
      break;
    default:
      m_internalWidget->setLayoutDirection(Qt::RightToLeft);
      qMdiSubWindow()->setLayoutDirection(Qt::RightToLeft);
      break;
  }
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setToolTipText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setToolTipText, SWING_ENV_ARG, JSTRING_ARG(text))
  m_internalWidget->setToolTip(QStringAdapter(env, text));
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setStatusTipText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setStatusTipText, SWING_ENV_ARG, JSTRING_ARG(text))
  m_internalWidget->setStatusTip(QStringAdapter(env, text));
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::setWhatsThisText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setWhatsThisText, SWING_ENV_ARG, JSTRING_ARG(text))
  m_internalWidget->setWhatsThis(QStringAdapter(env, text));
}

/*!
 * \inheritDoc
 */
bool InternalFrameDelegate::eventFilter(QObject *obj, QEvent *e)
{
  bool filtered = false;
  if (eventFilterEnabled()) {
    if (obj == qObject()) {
      switch ((int)e->type()) { // cast for QEvent::User types
        case QEvent::Enter:
          // falls through
        case QEvent::Leave:
          // falls through
        case QEvent::Resize:
          // falls through
        case QEvent::Paint:
          // falls through
        case QEvent::KeyPress:
          // falls through
        case QEvent::KeyRelease:
          // falls through
        case SwingKeyTypedEvent::TYPE:
          // falls through
        case QEvent::MouseButtonPress:
          // falls through
        case QEvent::MouseButtonRelease:
          // falls through
        case SwingMouseClickedEvent::TYPE:
          // falls through
        case QEvent::MouseButtonDblClick:
          // falls through
        case QEvent::ContextMenu:
          // falls through
        case QEvent::MouseMove:
          // falls through
        case QEvent::Wheel:
          // falls through
        case QEvent::FocusIn:
          // falls through
        case QEvent::FocusOut:
          break;
        default:
          filtered = WindowDelegate::eventFilter(obj, e);
          break;
      }
    } else {
      switch ((int)e->type()) { // cast for QEvent::User types
        case QEvent::Enter:
          ComponentDelegate::eventFilter(obj, e);
          break;
          // falls through
        case QEvent::Leave:
          // falls through
        case QEvent::Resize:
          // falls through
        case QEvent::Paint:
          // falls through
        case QEvent::KeyPress:
          // falls through
        case QEvent::KeyRelease:
          // falls through
        case SwingKeyTypedEvent::TYPE:
          // falls through
        case QEvent::MouseButtonPress:
          // falls through
        case QEvent::MouseButtonRelease:
          // falls through
        case SwingMouseClickedEvent::TYPE:
          // falls through
        case QEvent::MouseButtonDblClick:
          // falls through
        case QEvent::ContextMenu:
          // falls through
        case QEvent::MouseMove:
          // falls through
        case QEvent::Wheel:
          // falls through
        case QEvent::FocusIn:
          // falls through
        case QEvent::FocusOut:
          filtered = ComponentDelegate::eventFilter(obj, e);
          break;
        default:
          break;
      }
    }
  }
  return filtered;
}

/*!
 * \inheritDoc
 */
void InternalFrameDelegate::filterEnabledEvents()
{
  if (eventEnabled(SWING_EVENT(MOUSE_MOTION_EVENT_MASK))) {
    m_internalWidget->setMouseTracking(true); // not m_widget!
  } else {
    m_internalWidget->setMouseTracking(false); // not m_widget!
  }
}

/*!
 * \inheritDoc
 */
QWidget *InternalFrameDelegate::paintingWidget()
{
  return m_internalWidget;
}

// InternalFrameDelegate :: Private Static Data Members. -----------------------

jmethodID InternalFrameDelegate::sm_getLayoutPreferredSizeMID = 0;
